package com.angel.resourceBundle.managers;

import java.io.Serializable;
import java.util.Collection;

import org.apache.log4j.Logger;

import com.angel.dao.generic.exceptions.GenericDAOException;
import com.angel.dao.generic.exceptions.OnDeleteHibernateException;
import com.angel.dao.generic.interfaces.GenericDAO;
import com.angel.resourceBundle.contexts.ResourceBundleContext;
import com.angel.resourceBundle.daos.propertyValue.PropertyValueDAO;
import com.angel.resourceBundle.exceptions.OnRegisterPropertyValueException;
import com.angel.resourceBundle.exceptions.ResourceBundleException;
import com.angel.resourceBundle.propertyValue.PropertyValue;

public abstract class ResourceBundleManager {

	private static final Logger LOGGER = Logger.getLogger(ResourceBundleManager.class);

	private ResourceBundleContext resourceBundleContext;

	private GenericDAO<PropertyValue, Serializable> propertyValueDAO;

	protected abstract PropertyValue createPropertyValueInstance();

	@SuppressWarnings("unchecked")
	public <T extends PropertyValue, Code extends Serializable> ResourceBundleManager(ResourceBundleContext resourceBundleContext, GenericDAO<T, Code> propertyValueDAO){
		super();
		this.propertyValueDAO = (GenericDAO<PropertyValue, Serializable>) propertyValueDAO;
		this.resourceBundleContext = resourceBundleContext;
		this.resourceBundleContext.initializeContext();
	}

	public String getSeparator(){
		return this.resourceBundleContext.getKeySeparator();
	}

	public String getResourceBundleContextKey(String languageName){
		return this.resourceBundleContext.generateResourceBundleContextKey(languageName);
	}

	public String getResourceBundleContextKey(){
		return this.resourceBundleContext.generateResourceBundleContextKey();
	}

	public String getResourBundleContextType(){
		return this.resourceBundleContext.getResourceBundleManagerType();
	}

	public Boolean isResourBundleContextType(String resourceBunleContextType){
		return this.resourceBundleContext.isResourceBundleManagerType(resourceBunleContextType);
	}

	/** Register a property value instance.
	 *
	 * @param propertyValue to register.
	 * @throws ResourceBundleException when an error occurs persisting property value.
	 */
	protected void registerPropertyValue(PropertyValue propertyValue) throws OnRegisterPropertyValueException{
		try {
			LOGGER.info("Persisting property value.");
			this.getPropertyValueDAO().persist(propertyValue);
			LOGGER.info("Property value persisted.");
		} catch (GenericDAOException e) {
			throw new OnRegisterPropertyValueException("An error occured persisting property value.", e);
		}
	}

	public void removeAllPropertiesValues() throws ResourceBundleException {
		try {
			Long count = this.getPropertyValueDAO().count();
			LOGGER.info("Removing [" + count + "] properties values instances for resource bundle context [" + this.getResourceBundleContext().generateResourceBundleContextKey() + "].");
			this.getPropertyValueDAO().deleteAll();
		} catch (OnDeleteHibernateException e){
			throw new ResourceBundleException("Error occurred removing properties values.",e);
		}
	}

	/**
	 * @return the resourceBundleContext
	 */
	protected ResourceBundleContext getResourceBundleContext() {
		return resourceBundleContext;
	}

	/**
	 * @param resourceBundleContext the resourceBundleContext to set
	 */
	protected void setResourceBundleContext(ResourceBundleContext resourceBundleContext) {
		this.resourceBundleContext = resourceBundleContext;
	}

	/**
	 * @return the propertyValueDAO
	 */
	@SuppressWarnings("unchecked")
	protected <T extends PropertyValue, H extends Serializable> PropertyValueDAO<T, H> getPropertyValueDAO() {
		return (PropertyValueDAO<T, H>) propertyValueDAO;
	}

	@SuppressWarnings("unchecked")
	protected <T extends PropertyValue, H extends Serializable> PropertyValueDAO<T, H> getPropertyValueDAO(Class<T> propertyValueClass) {
		return (PropertyValueDAO<T, H>) propertyValueDAO;
	}

	/**
	 * @param propertyValueDAO the propertyValueDAO to set
	 */
	@SuppressWarnings("unchecked")
	protected <T extends PropertyValue, H extends Serializable> void setPropertyValueDAO(PropertyValueDAO<T, H> propertyValueDAO) {
		this.propertyValueDAO = (GenericDAO<PropertyValue, Serializable>) propertyValueDAO;
	}

	public Boolean containsPropertyValueFor(String propertyValueKey){
		String extendedKey = this.getResourceBundleContext().generateExtendedKey(propertyValueKey);
		PropertyValue propertyValue = this.getPropertyValueDAO().findUniqueByExtendedKey(extendedKey);
		return propertyValue != null;
	}

	/** Find an unique property value for a property key and its current resource bundle context language.
	 *
	 * @param propertyValueKey to find.
	 * @return a property value with a property key associated with current resource bundle language.
	 */
	public PropertyValue findUniquePropertyValueFor(String propertyValueKey){
		String extendedKey = this.getResourceBundleContext().generateExtendedKey(propertyValueKey);
		return this.getPropertyValueDAO().findUniqueByExtendedKey(extendedKey);
	}

	/** Find an unique property value for a property key and its language name. This language can be or not current resource bundle
	 * context language name.
	 *
	 * @param languageName to find property value.
	 * @param propertyValueKey associated to property value.
	 * @return a property value with a property key associated with a language.
	 */
	public PropertyValue findUniquePropertyValueForLanguajeName(String languageName, String propertyValueKey){
		String extendedKey = this.getResourceBundleContext().generateExtendedKey(propertyValueKey, languageName);
		return this.getPropertyValueDAO().findUniqueByExtendedKey(extendedKey);
	}

	/** Find all properties values for a languages.
	 *
	 * @param languageName to find all its properties values.
	 * @return a properties values collection.
	 */
	public Collection<PropertyValue> findAllPropertiesValuesForLanguageName(String languageName){
		String resourceBundleContextKey = this.getResourceBundleContext().generateResourceBundleContextKey(languageName);
		return this.getPropertyValueDAO().findAllByResourceBundleContextKey(resourceBundleContextKey);
	}

	/** Find all properties values for a property value array and a specific language name.
	 *
	 * @param languageName to find its properties values keys.
	 * @param propertiesKeys to find its properties values.
	 * @return a properties values collection.
	 */
	public Collection<PropertyValue> findAllPropertiesValuesForLanguageName(String languageName, String[] propertiesKeys){
		String[] extendedKeys = this.getResourceBundleContext().generateExtendedKey(propertiesKeys, languageName);
		return this.getPropertyValueDAO().findAllByExtendedKey(extendedKeys);
	}

	/** Find all properties values for a property key array and its current resource bundle context language.
	 *
	 * @param propertiesValuesKey array with properties values keys.
	 * @return a properties values collection.
	 */
	public Collection<PropertyValue> findAllPropertiesValuesByArrayFor(String[] propertiesValuesKey){
		String[] extendedKeys = this.getResourceBundleContext().generateExtendedKey(propertiesValuesKey);
		return this.getPropertyValueDAO().findAllByExtendedKey(extendedKeys);
	}

	/** Find all properties values for a property key array and its current resource bundle context language.
	 *
	 * @param propertiesValuesKey array with properties values keys.
	 * @return a properties values collection.
	 */
	public Collection<PropertyValue> findAllPropertiesValuesFor(String ... propertiesValuesKey){
		String[] extendedKeys = this.getResourceBundleContext().generateExtendedKey(propertiesValuesKey);
		return this.getPropertyValueDAO().findAllByExtendedKey(extendedKeys);
	}

	/** Find all properties values for a property key collection and its current resource bundle context language.
	 *
	 * @param propertiesValuesKey collection with properties values keys.
	 * @return a properties values collection.
	 */
	public Collection<PropertyValue> findAllPropertiesValuesFor(Collection<String> propertiesValuesKey){
		String[] keysArray = (String[]) new Object[]{propertiesValuesKey.toArray()};
		String[] extendedKeys = this.getResourceBundleContext().generateExtendedKey(keysArray);
		return this.getPropertyValueDAO().findAllByExtendedKey(extendedKeys);
	}
}
